﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using SteamFluentAPI.Infrastructure;
using SteamFluentAPI.Infrastructure.Base;

namespace SteamFluentAPI.Builder
{
    /// <summary>
    /// Handles the construction of the SteamRequest method and also filters the list of parameters available.
    /// </summary>
    /// <typeparam name="M"></typeparam>
    public class SteamMethodBuilder<M> where M : SteamMethod
    {
        private SteamRequest request;
        public SteamMethodBuilder(SteamRequest request)
        {
            this.request = request;
        }

        /// <summary>
        /// Gets the entity object that maps properties returned from a steam request.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="numberOfRetries"></param>
        /// <returns></returns>
        public T GetEntity<T>(Expression<Func<M, T>> entity, int numberOfRetries = 3) where T: SteamEntity
        {
            string response = this.GetRequest(numberOfRetries);
            return JsonConvert.DeserializeObject<T>(response);
        }

        /// <summary>
        /// Gets the url string used to request api.steampowered.com.
        /// </summary>
        /// <returns></returns>
        public string GetRequestString()
        {
            if (request.SteamMethod == null)
            {
                request.SteamMethod = Activator.CreateInstance<M>();
                request.RequiredParameters = request.SteamMethod.GetRequiredParameters();
            }
            return request.GetRequestString();
        }

        /// <summary>
        /// Returns the result of the request in the specified SteamRequestFormat
        /// </summary>
        /// <param name="numberOfRetries"></param>
        /// <returns></returns>
        public string GetRequest(int numberOfRetries = 3)
        {
            if (request.SteamMethod == null)
            {
                request.SteamMethod = Activator.CreateInstance<M>();
                request.RequiredParameters = request.SteamMethod.GetRequiredParameters();
            }
            return request.GetRequest(numberOfRetries);
        }

        /// <summary>
        /// Adds parameters available for the current method to the request.
        /// </summary>
        /// <param name="handle"></param>
        /// <returns></returns>
        public SteamMethodBuilder<M> Parameters(Action<M> handle)
        {
            M method = Activator.CreateInstance<M>();
            handle(method);
            request.SteamMethod = method;

            foreach (KeyValuePair<string, object> parameter in method.GetParameters())
            {
                if (request.Parameters.Keys.Contains(parameter.Key))
                {
                    request.Parameters[parameter.Key] = parameter.Value;
                }
                else
                {
                    request.Parameters.Add(parameter.Key, parameter.Value);
                }
            }

            request.RequiredParameters = method.GetRequiredParameters();
            return this;
        }

        #region Hiding Methods

        [EditorBrowsable(EditorBrowsableState.Never)]
        public override Boolean Equals(Object obj)
        {
            return base.Equals(obj);
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public override Int32 GetHashCode()
        {
            return base.GetHashCode();
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public override String ToString()
        {
            return base.ToString();
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public new Type GetType()
        {
            return base.GetType();
        }

        #endregion
    }
}
